package com.ssy.lingxi.enhance.serviceimpl.process;

import com.querydsl.core.BooleanBuilder;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.enhance.api.model.dto.AddLogisticsDTO;
import com.ssy.lingxi.enhance.api.model.dto.ConfirmLogisticsDTO;
import com.ssy.lingxi.enhance.constant.*;
import com.ssy.lingxi.enhance.entity.*;
import com.ssy.lingxi.enhance.handler.async.MessageAsyncService;
import com.ssy.lingxi.enhance.handler.async.ReportAsyncService;
import com.ssy.lingxi.enhance.handler.jpa.QueryDslUtil;
import com.ssy.lingxi.enhance.model.qo.ProduceNoticeOrderQO;
import com.ssy.lingxi.enhance.model.vo.ProduceNoticeOrderListVO;
import com.ssy.lingxi.enhance.repository.InnerWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.OuterWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.PNOReceiveDeliverDetailRepository;
import com.ssy.lingxi.enhance.repository.ProduceNoticeOrderRepository;
import com.ssy.lingxi.enhance.service.process.ProcessToBeAddLogisticsService;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.report.api.enums.EnhanceProcessOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 加工能力 - 确认生产通知单(加工企业) - 待新增物流单 - 业务实现层
 * @author fhj
 * @date 2020/10/20
 * @version 2.0.0
 */
@Slf4j
@Service
public class ProcessToBeAddLogisticsServiceImpl implements ProcessToBeAddLogisticsService {

    @Resource
    private ProcessFeign processFeign;
    @Resource
    private QueryDslUtil queryDslUtil;
    @Resource
    private ProduceNoticeOrderRepository produceNoticeOrderRepository;
    @Resource
    private PNOReceiveDeliverDetailRepository pnoReceiveDeliverDetailRepository;
    @Resource
    private InnerWorkflowRecordRepository innerWorkflowRecordRepository;
    @Resource
    private OuterWorkflowRecordRepository outerWorkflowRecordRepository;
    @Resource
    private ReportAsyncService reportAsyncService;
    @Resource
    private MessageAsyncService messageAsyncService;

    /**
     * 列表
     * */
    @Override
    public Wrapper<PageData<ProduceNoticeOrderListVO>> list(ProduceNoticeOrderQO qo, UserLoginCacheDTO user) {
        //查询表实体 - 生产通知单
        QProduceNoticeOrderDO pno = QProduceNoticeOrderDO.produceNoticeOrderDO;

        //查询条件构造 - 必要条件
        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(pno.processMemberId.eq(user.getMemberId()));
        predicates.and(pno.processRoleId.eq(user.getMemberRoleId()));
        predicates.and(pno.outerStatus.eq(PNOOuterStatusEnum.TO_BE_ADD_LOGISTICS.getCode()));

        return Wrapper.success(queryDslUtil.getProcessPNOList(qo, pno, predicates));
    }

    /**
     * 内部接口：提交物流单
     * */
    @Override
    @Transactional
    public Wrapper<Void> submit(AddLogisticsDTO dto) {
        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getProduceNoticeOrderId()).orElse(null);
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }

        //根据ID获取生产通知单收发货明细
        PNOReceiveDeliverDetailDO pnoReceiveDeliverDetailDO = pnoReceiveDeliverDetailRepository.findByProduceNoticeOrderIdAndDeliverStatus(produceNoticeOrder.getId(), DeliverStatusEnum.TO_BE_CONFIRM_DELIVERY.getCode());
        if(pnoReceiveDeliverDetailDO == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO_RECEIVE_DELIVER_DETAIL);
        }

        //更新生产通知单收发货明细物流公司、物流单号、物流单ID
        pnoReceiveDeliverDetailDO.setLogisticsCompany(dto.getCompanyName());
        pnoReceiveDeliverDetailDO.setLogisticsOrderNo(dto.getLogisticsOrderNo());
        pnoReceiveDeliverDetailDO.setLogisticsOrderId(dto.getLogisticsOrderId());
        pnoReceiveDeliverDetailRepository.saveAndFlush(pnoReceiveDeliverDetailDO);

        //更新生产通知单物流单号、物流单ID、状态、加工企业内部状态
        produceNoticeOrder.setLogisticsOrderNo(dto.getLogisticsOrderNo());
        produceNoticeOrder.setLogisticsOrderId(dto.getLogisticsOrderId());
        produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_PROCESS_CONFIRM_LOGISTICS.getCode());
        produceNoticeOrder.setProcessInnerStatus(PNOProcessInnerStatusEnum.TO_BE_CONFIRM_LOGISTICS.getCode());
        produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                produceNoticeOrder.getProcessMemberId(), produceNoticeOrder.getProcessRoleId(), OperateDataSourceEnum.ENHANCE_PROCESS.getCode(),
                null,  null,
                EnhanceProcessOperateTypeEnum.TO_BE_ADD_LOGISTICS.getCode(), 1L
        );

        return Wrapper.success();
    }

    /**
     * 内部接口：确认物流单
     */
    @Override
    @Transactional
    public Wrapper<Void> confirmLogistics(ConfirmLogisticsDTO dto) {
        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getProduceNoticeOrderId()).orElse(null);
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }

        //不接受物流单，更新状态、加工企业内部状态
        if(dto.getStatus().equals(LogisticsConfirmTypeEnum.NOT.getCode())) {
            produceNoticeOrder.setStatus(PNOAllStatusEnum.NOT_ACCEPTED_LOGISTICS.getCode());
            produceNoticeOrder.setProcessInnerStatus(PNOProcessInnerStatusEnum.NOT_ACCEPTED_LOGISTICS.getCode());
            produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);
            return Wrapper.success();
        }

        //待确认物流单，更新状态、加工企业内部状态
        if(dto.getStatus().equals(LogisticsConfirmTypeEnum.TO_BE_CONFIRM.getCode())) {
            produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_PROCESS_CONFIRM_LOGISTICS.getCode());
            produceNoticeOrder.setProcessInnerStatus(PNOProcessInnerStatusEnum.TO_BE_CONFIRM_LOGISTICS.getCode());
            produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);
            return Wrapper.success();
        }

        //接受物流单
        //调用工作流服务 -> 执行外部流程
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
        taskExecuteVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
        taskExecuteVO.setDataId(produceNoticeOrder.getId());
        taskExecuteVO.setTaskId(produceNoticeOrder.getOuterTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
        taskExecuteVO.setProcessKey(produceNoticeOrder.getOuterProcessKey());
        Wrapper<SimpleTaskCompleteVO> outerWrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == outerWrapper.getCode()) {
            //记录外部工作流记录
            OuterWorkflowRecordDO outerWorkflowRecordDO = new OuterWorkflowRecordDO();
            outerWorkflowRecordDO.setProduceNoticeOrderId(produceNoticeOrder.getId());
            outerWorkflowRecordDO.setUserId(dto.getUser().getUserId());
            outerWorkflowRecordDO.setMemberId(dto.getUser().getMemberId());
            outerWorkflowRecordDO.setRoleId(dto.getUser().getMemberRoleId());
            outerWorkflowRecordDO.setStep(produceNoticeOrder.getOuterStatus());
            outerWorkflowRecordDO.setRoleName(dto.getUser().getMemberRoleName());
            outerWorkflowRecordDO.setStatus("待发货生产通知单");
            outerWorkflowRecordDO.setOperate("新增物流单");
            outerWorkflowRecordDO.setOperateTime(System.currentTimeMillis());
            outerWorkflowRecordDO.setOpinion("物流单号：" + dto.getLogisticsOrderNo());
            outerWorkflowRecordRepository.saveAndFlush(outerWorkflowRecordDO);

            //记录加工企业内部工作流记录
            InnerWorkflowRecordDO innerWorkflowRecord = new InnerWorkflowRecordDO();
            innerWorkflowRecord.setProduceNoticeOrderId(produceNoticeOrder.getId());
            innerWorkflowRecord.setUserId(dto.getUser().getUserId());
            innerWorkflowRecord.setMemberId(dto.getUser().getMemberId());
            innerWorkflowRecord.setRoleId(dto.getUser().getMemberRoleId());
            innerWorkflowRecord.setType(RoleTypeEnum.PROCESS.getCode());
            innerWorkflowRecord.setStep(produceNoticeOrder.getStatus());
            innerWorkflowRecord.setOperator(dto.getUser().getUserName());
            innerWorkflowRecord.setDepartment(dto.getUser().getUserOrgName());
            innerWorkflowRecord.setJobTitle(dto.getUser().getUserJobTitle());
            innerWorkflowRecord.setStatus("接受物流单");
            innerWorkflowRecord.setOperate("新增物流单");
            innerWorkflowRecord.setOperateTime(System.currentTimeMillis());
            innerWorkflowRecord.setOpinion("物流单号：" + dto.getLogisticsOrderNo());
            innerWorkflowRecordRepository.saveAndFlush(innerWorkflowRecord);

            //更新外部状态、外部任务ID、状态、加工企业内部状态
            produceNoticeOrder.setOuterStatus(outerWrapper.getData().getStatus());
            produceNoticeOrder.setOuterTaskId(outerWrapper.getData().getTaskId());
            produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_PROCESS_CONFIRM_DELIVERY.getCode());
            produceNoticeOrder.setProcessInnerStatus(PNOProcessInnerStatusEnum.TO_BE_CONFIRM_DELIVERY.getCode());
            produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);
        }else {
            log.error("工作流服务异常:" + outerWrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }

        //调用报表服务、消息服务 -> 新增操作通知、发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                produceNoticeOrder.getProcessMemberId(), produceNoticeOrder.getProcessRoleId(), OperateDataSourceEnum.ENHANCE_PROCESS.getCode(),
                EnhanceProcessOperateTypeEnum.TO_BE_DELIVERY.getCode(),  1L,
                null, null
        );
        messageAsyncService.sendSystemMessage(produceNoticeOrder.getProcessMemberId(), produceNoticeOrder.getProcessRoleId(),
                MessageTemplateCode.production_order_handle_shipment, Stream.of(produceNoticeOrder.getNoticeNo(), produceNoticeOrder.getSummary()).collect(Collectors.toList())
        );

        return Wrapper.success();
    }
}
